package com.itheima.utils;


import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.support.XmlWebApplicationContext;

import java.util.Properties;

/**
 * @Author likepei
 * @Date 2020/1/17 15:52
 * @Version v1.0
 * @Description 配置中心工具类
 */
public class SettingCenterUtil extends PropertyPlaceholderConfigurer implements ApplicationContextAware {

    private XmlWebApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (XmlWebApplicationContext)applicationContext;
    }


    /**
     * 此方法用于 处理properties属性文件内容,
     * 作用相当于此标签
     * <context:property-placeholder location="classpath:jdbc.properties"/>
     */
    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException {
        //载入ZooKeeper配置文件
        loadZooKeeper(props);
        //添加watch监听
        addWatch(props);

        super.processProperties(beanFactoryToProcess, props);
    }

    /**
     * 添加watch机制
     * 步骤:
     * 1.创建重试策略
     * 2.创建客户端
     * 3.启动客户端
     * 4.创建缓存机制,监听zooKeeper中的 /config路径
     * 5.启动缓存机制
     * 6.添加监听
     */
    private void addWatch(Properties props) {
        //创建重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 1);
        //创建客户端
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 1000, 1000, retryPolicy);
        //启动客户端
        client.start();
        //创建缓存机制,监听zooKeeper中的 /config路径
        TreeCache treeCache = new TreeCache(client, "/config");
        //启动缓存机制
        try {
            treeCache.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //添加监听
        treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                //处理 ZooKeeper中 /config节点中的更新事件
                if (event.getType() == TreeCacheEvent.Type.NODE_UPDATED){
                    String path = event.getData().getPath();
                    String data = new String( event.getData().getData() );

                    //对应的修改 驱动,url,用户名,密码数据
                    if("/config/jdbc.driverClassName".equals(path)){
                        props.setProperty("jdbc.driverClassName", data);
                    } else if("/config/jdbc.url".equals(path)){
                        props.setProperty("jdbc.url", data);
                    } else if("/config/jdbc.username".equals(path)){
                        props.setProperty("jdbc.username", data);
                    } else if("/config/jdbc.password".equals(path)){
                        props.setProperty("jdbc.password", data);
                    }

                    //更新Spring容器, 必须更新
                    applicationContext.refresh();
                }
            }
        });
    }

    /**
     * 加载ZooKeeper数据
     * 步骤:
     * 1.创建重试策略
     * 2.创建客户端
     * 3.启动客户端
     * 4.获取ZooKeeper中的节点数据(驱动,url,用户名,密码)赋值给props
     */
    private void loadZooKeeper(Properties props) {
        //创建重试策略
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 1);
        //创建客户端
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 1000, 1000, retryPolicy);
        //启动客户端
        client.start();
        //获取ZooKeeper中的节点数据(驱动,url,用户名,密码)赋值给props
        try {
            byte[] driver = client.getData().forPath("/config/jdbc.driverClassName");
            byte[] url = client.getData().forPath("/config/jdbc.url");
            byte[] username = client.getData().forPath("/config/jdbc.username");
            byte[] password = client.getData().forPath("/config/jdbc.password");
            //赋值给props
            props.setProperty("jdbc.driverClassName", new String(driver));
            props.setProperty("jdbc.url", new String(url));
            props.setProperty("jdbc.username", new String(username));
            props.setProperty("jdbc.password", new String(password));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
